#pragma once
#include <iostream>
#include <unistd.h>
#include <assert.h>
#include <string>
#include <vector>
#include <thread>
#include <event.h>
#include <memory>
#include <functional>
#include <mutex>
#include <sys/eventfd.h>

#include "../Log.hpp"
#include "Channel.hpp"
#include "Epoller.hpp"
#include "TimerWheel.hpp"

class EventLoop
{
private:
    std::thread::id _thread_id;                // 线程id
    Epoller _epoller;                          // epoll对象
    int _eventfd;                              // 用于程序内部通信的文件描述符
    std::unique_ptr<Channel> _eventfd_channel; // 管理eventfd文件描述符的Channel

    using Functor = std::function<void()>;
    std::vector<Functor> _tasks; // 任务队列
    std::mutex _mutex;           // 保证任务队列的线程安全
    TimerWheel _timer_wheel;     // 时间轮

    // 创建一个eventfd文件描述符对象
    static int CreateEventfd()
    {
        // 将文件描述符的属性设置为非阻塞
        int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd < 0)
        {
            ERR_LOG("create eventfd fail");
            abort();
        }
        return efd;
    }
    // eventfd读事件就绪的回调函数
    void ReadEventCallBack()
    {
        // 将数据取出来即可
        uint64_t val = 0;
        ssize_t ret = read(_eventfd, &val, sizeof(val));
        if (ret <= 0)
        {
            // 被信号打断了
            if (errno == EAGAIN || errno == EINTR)
                return;
            ERR_LOG("read eventfd fail");
            abort();
        }
    }
    // 向eventfd写入数据的函数
    void WeakUpEventfd()
    {
        uint64_t val = 1;
        ssize_t ret = write(_eventfd, &val, sizeof(val));
        if (ret < 0)
        {
            if (errno == EINTR)
                return;
            ERR_LOG("write eventfd fail");
            abort();
        }
    }
    // 执行任务队列中的所有任务
    void RunAllTask()
    {
        std::vector<Functor> functors;
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.swap(functors);
        }
        for (auto &task : functors)
        {
            task();
        }
    }

public:
    EventLoop()
        : _thread_id(std::this_thread::get_id()), _eventfd_channel(new Channel(this, _eventfd)), _eventfd(CreateEventfd()), _timer_wheel(this)
    {
        // 设置读事件回调函数
        _eventfd_channel->SetReadCallBack(std::bind(&EventLoop::ReadEventCallBack, this));
        // 启动读事件监控
        _eventfd_channel->EnableRead();
    }
    ~EventLoop() = default;

    // 启动Reactor服务
    void StartReactor()
    {
        while(1)
        {
            // 1. 启动epoll事件监控
            std::vector<Channel *> active;
            _epoller.StartEpoll(&active);
            // 2. 处理事件
            for (auto &channel : active)
            {
                channel->HandleEvent();
            }
            // 3. 执行任务队列中的任务
            RunAllTask();
        }
    }

    // 判断当前线程是否是EventLoop对应的线程
    bool IsInLoop() { return _thread_id == std::this_thread::get_id(); }
    void AssertInLoop() { assert(_thread_id == std::this_thread::get_id()); }

    // 判断任务是否能够现在执行
    void RunInLoop(const Functor &task_cb)
    {
        if (IsInLoop())
            task_cb();
        return QueuePushInLoop(task_cb);
    }
    // 将任务压入到任务队列中
    void QueuePushInLoop(const Functor &task_cb)
    {
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.push_back(task_cb);
        }
        // 通过向eventfd写入数据，唤醒有可能没事件就绪，而导致epoll阻塞而无法调用start函数执行任务队列中的任务
        WeakUpEventfd();
    }

    // 添加修改描述符事件监控
    void UpdateEvent(Channel *channel) { _epoller.UpdateEvent(channel); }
    // 移除描述符的事件监控
    void RemoveEvent(Channel *channel) { _epoller.RemoveEvent(channel); }

    // 判断是否有该任务
    bool HasTiemrTask(uint64_t task_id) { return _timer_wheel.HasTiemrTask(task_id); }
    // 添加定时任务
    void TimerAdd(uint64_t task_id, int delay, const Functor &cb) { _timer_wheel.TimerAdd(task_id, delay, cb); }
    // 刷新定时任务
    void TimerRefresh(uint64_t task_id) { _timer_wheel.TimerRefresh(task_id); }
    // 取消定时任务
    void TimerCancel(uint64_t task_id) { _timer_wheel.TimerCancel(task_id); }
};

// Channel函数
// 更新事件监控
void Channel::Update()
{
    _ep->UpdateEvent(this);
}
// 移除事件监控
void Channel::Remove()
{
    _ep->RemoveEvent(this);
}

// TimerWheel函数
// 添加定时任务（并非真的添加，而是作为任务放入任务队列）
void TimerWheel::TimerAdd(uint64_t task_id, int delay, const TaskFunc &cb)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAdd, this, task_id, delay, cb));
}
// 刷新定时任务
void TimerWheel::TimerRefresh(uint64_t task_id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefresh, this, task_id));
}
// 取消定时任务
void TimerWheel::TimerCancel(uint64_t task_id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCancel, this, task_id));
}
